package sess

import (
	"context"
	"net"

	"src/zeus/iserver"
	"src/zeus/threads"

	kcp "github.com/xtaci/kcp-go"
)

func newNetSrv(protocal string, msgDeliver IConnReceiver, info iserver.PortInfo) INetSrv {
	if protocal == "tcp" || protocal == "kcp" {
		return newARQNetSrv(protocal, msgDeliver, info)
	}
	return nil
}

// INetSrv 网络监听
type INetSrv interface {
	start() error
	close()
	//获取使用的端口
	GetPort() int
	// 对外的端口
	GetEtcdPort() int
}

// IConnReceiver 连接接收
type IConnReceiver interface {
	acceptConn(net.Conn)
}

///////////////////////////////////////////////////////////////////

// ARQNetSrv 网络服务器
type ARQNetSrv struct {
	protocal string
	listener net.Listener
	receiver IConnReceiver
	thgo     *threads.ThreadGo

	info iserver.PortInfo
	port int
}

func newARQNetSrv(protocal string, receiver IConnReceiver, info iserver.PortInfo) INetSrv {
	srv := &ARQNetSrv{
		protocal: protocal,
		receiver: receiver,
		info:     info,
	}
	srv.thgo = threads.NewThreadGo()
	srv.listener, srv.port = GetListener(protocal, info)
	return srv
}

func (srv *ARQNetSrv) start() error {

	srv.thgo.Go(srv.acceptConn)

	return nil
}

func (srv *ARQNetSrv) close() {
	srv.listener.Close()
	srv.thgo.CloseWait()
}

func (srv *ARQNetSrv) acceptConn(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return
		default:
			{
				conn, err := srv.listener.Accept()
				if err != nil {
					// logger.Error("accept connection error ", err)
					continue
				}
				if srv.protocal == "kcp" {
					udpSession := conn.(*kcp.UDPSession)
					if udpSession != nil {
						udpSession.SetStreamMode(true)
						udpSession.SetWindowSize(10*1024, 10*1024)
						udpSession.SetNoDelay(1, 10, 2, 1)
						udpSession.SetDSCP(46)
						udpSession.SetMtu(1400)
						udpSession.SetACKNoDelay(false)
					}
				}
				// srv.thgo.Go(func(ctx context.Context) {
				srv.receiver.acceptConn(conn)
				// })
			}
		}
	}
}

// 获取连接的端口
func (this *ARQNetSrv) GetPort() int {
	return this.port
}

// 对外的端口
func (this *ARQNetSrv) GetEtcdPort() int {
	if this.info.ParamPort == 0 {
		return this.port
	} else {
		return this.info.ParamPort
	}
}
